package login

import (
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	. "go_tempate/SQL/redis"
	. "go_tempate/SQL/table"
	. "go_tempate/common/function"
	. "go_tempate/common/store"
	. "go_tempate/common/struct"
	. "go_tempate/config"
	"net/http"
	"strconv"
)

// 用户密码验证
// ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
func Login(ctx *gin.Context) {
	user := User{} // 声明用户结构体

	body := ObtainResponseBody(ctx) // 获取当前的返回结构体

	err := ObtainRequestContent(ctx, body, &user) // 进行获取并验证当前请求体中的数据

	//如果出现报错
	//----------------------------------------------------------------------------------------------------------
	if err != nil {
		return
	}

	//从数据库中查找是否有此登录账号
	//----------------------------------------------------------------------------------------------------------
	userInfo := UserInfo{} // 声明用户信息查询表
	logInfo := LoginInfo{} // 声明登录信息查询表

	_ = logInfo.OnceLoginInfoInAccount(user.Account)

	//如果数据库中没有此用户信息
	if logInfo.Account == "" {
		//进行批量设置当前返回结构体
		body.BatchSettings(NotUserInfo, NotUserInfoMessage, nil)
		return
	}

	//比对密码是否正确(首先进行前端密码字节串的字符串化)
	//----------------------------------------------------------------------------------------------------------
	ok, err := ComparePasswordAndHash(AssemblePePassword(user.Password), logInfo.Password)

	if err != nil {
		body.BatchSettings(PasswordErr, TokenParsingFailed, nil)
	}

	//进行比较用户是否密码与用户名匹配
	//----------------------------------------------------------------------------------------------------------
	if user.Account == logInfo.Account && ok {
		//查询到对应的用户信息
		_ = userInfo.OnceLoginIdFromUser(logInfo.ID)

		//生成当前的用户token，因为需要直接用用户信息故存入 userInfo表中的id
		//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
		token, err := JwtCreateToken(DefaultCustomClaims(userInfo.ID, AccessTokenEffectiveTime))

		//如果生成失败
		if err != nil {
			//进行批量设置当前返回结构体
			body.BatchSettings(Error, TokenGenerationFailed, nil)
			return
		}

		//修改登录状态
		//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
		err = logInfo.SetLoginInfoState(1)

		if err != nil {
			//进行批量设置当前返回结构体
			body.BatchSettings(Error, UserLoginStateModificationFailed, nil)
			return
		}

		//将token同步到响应体+redis中
		//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
		//创建成功后重新更新redis中的缓存数据，且延迟期限
		err = SetRedisItems(strconv.Itoa(int(userInfo.ID)), token, RefreshEffectiveTime)
		if err != nil {
			//修改响应体内容
			body.BatchSettings(Error, TokenJoinRedisError, nil)
			return
		}

		body.Message = "登陆成功！"
		body.Token = token

		zap.S().Infof("%v用户登陆成功，生成token为:%v", userInfo.Name, token)

	} else {
		//进行批量设置当前返回结构体
		body.Message = UserPasswordError
	}
}

// 退出登陆
// ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
func LoginOut(ctx *gin.Context) {
	body := ObtainResponseBody(ctx) // 获取当前的返回结构体

	//用户信息集中操作
	//----------------------------------------------------------------------------------------------------------
	user, err := ObtainUserInfo(ctx, body) // 获取当前查询的用户信息

	//如果错误则弹出
	if err != nil {
		return
	}

	//判断用户是否已经退出了
	//----------------------------------------------------------------------------------------------------------
	if user.LoginInfo.State == 0 {
		body.BatchSettings(LoginErr, UserNotLogin, nil)
		body.Status = http.StatusUnauthorized
		return
	}

	//进行入库修改
	//----------------------------------------------------------------------------------------------------------
	err = user.LoginInfo.SetLoginInfoState(0)

	if err != nil {
		body.BatchSettings(Error, UserExitLoginError, nil)
		return
	}

	//修改 响应体信息 + 情况登录记录
	//----------------------------------------------------------------------------------------------------------
	err = DeleteRedisItem(strconv.Itoa(int(user.ID)))

	if err != nil {
		body.BatchSettings(Error, DeleteTokenInRedisError, nil)
		return
	}

	body.Message = "退出成功"
	zap.S().Infof("%v用户退出成功", user.Name)
}
